package io.plus.utils;

import io.plus.utils.thread.lock_capable_task.CallerRunsPolicyImpl;
import io.plus.utils.thread.lock_capable_task.DefaultThreadFactory;
import io.plus.utils.thread.lock_capable_task.LockCapableRunnableThreadPoolExecutor;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
import java.util.concurrent.TimeUnit;


public class Threads {
    public static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
    public static final int CORE_POOL_SIZE = AVAILABLE_PROCESSORS * 1;
    public static final int MAX_POOL_SIZE_FOR_TIO = Math.max(CORE_POOL_SIZE * 3, 64);
    public static final int MAX_POOL_SIZE_FOR_GROUP = Math.max(CORE_POOL_SIZE * 16, 256);
    public static final long KEEP_ALIVE_TIME = 0L;                                            //360000L;
    @SuppressWarnings("unused")
    private static final int QUEUE_CAPACITY = 1000000;
    private static ThreadPoolExecutor threadPoolExecutor = null;
    private static LockCapableRunnableThreadPoolExecutor lockCapableRunnableThreadPoolExecutor = null;


    private Threads() {
    }


    public static ThreadPoolExecutor getThreadPoolExecutor() {
        if (threadPoolExecutor != null) {
            return threadPoolExecutor;
        }

        synchronized (Threads.class) {
            if (threadPoolExecutor != null) {
                return threadPoolExecutor;
            }

            LinkedBlockingQueue<Runnable> runnableQueue = new LinkedBlockingQueue<>();

            String threadName = "tio-group";
            DefaultThreadFactory defaultThreadFactory = DefaultThreadFactory.getInstance(threadName, Thread.MAX_PRIORITY);
            CallerRunsPolicy callerRunsPolicy = new CallerRunsPolicyImpl();
            threadPoolExecutor = new ThreadPoolExecutor(MAX_POOL_SIZE_FOR_GROUP, MAX_POOL_SIZE_FOR_GROUP, KEEP_ALIVE_TIME, TimeUnit.SECONDS, runnableQueue, defaultThreadFactory,
                    callerRunsPolicy);

            threadPoolExecutor.prestartCoreThread();

            return threadPoolExecutor;
        }
    }


    public static LockCapableRunnableThreadPoolExecutor getLockCapableRunnableThreadPoolExecutor() {
        if (lockCapableRunnableThreadPoolExecutor != null) {
            return lockCapableRunnableThreadPoolExecutor;
        }

        synchronized (Threads.class) {
            if (lockCapableRunnableThreadPoolExecutor != null) {
                return lockCapableRunnableThreadPoolExecutor;
            }

            LinkedBlockingQueue<Runnable> runnableQueue = new LinkedBlockingQueue<>();

            String threadName = "tio-worker";
            DefaultThreadFactory defaultThreadFactory = DefaultThreadFactory.getInstance(threadName, Thread.MAX_PRIORITY);
            CallerRunsPolicy callerRunsPolicy = new CallerRunsPolicyImpl();
            lockCapableRunnableThreadPoolExecutor = new LockCapableRunnableThreadPoolExecutor(MAX_POOL_SIZE_FOR_TIO, MAX_POOL_SIZE_FOR_TIO, KEEP_ALIVE_TIME, runnableQueue, defaultThreadFactory, threadName,
                    callerRunsPolicy);

            lockCapableRunnableThreadPoolExecutor.prestartCoreThread();

            return lockCapableRunnableThreadPoolExecutor;
        }
    }
}
